/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.mnt.websocket;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.storeChat.domain.ChatMessages;
import me.zhengjie.modules.storeChat.repository.ChatMessagesRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.gson.GsonBuilderCustomizer;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


@ServerEndpoint("/webSocket/{username}")
@Slf4j
@Component
@Service
@RequiredArgsConstructor
public class ChatSocket {


    @Autowired
    private ChatMessagesRepository chatMessageRepository;

    private static ChatMessagesRepository chatMessageRepositoryStatic;

    @PostConstruct
    private void init () {
        chatMessageRepositoryStatic = chatMessageRepository;
    }
//    @PostConstruct
//    public void postConstruct() {
//        if (chatMessageRepository == null) {
//            log.error("ChatMessagesRepository is null");
//        }else{
//            log.error("ChatMessagesRepository is not null");
//
//        }
//    }

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。  读多写少的情境下好
    private static CopyOnWriteArraySet<ChatSocket> webSocketSet = new CopyOnWriteArraySet<ChatSocket>();

    // 存储所有的用户连接
    private static final Map<String, Session> WEBSOCKET_MAP = new ConcurrentHashMap<>();

    // 存储所有的用户信息，读写都可以 分段锁
    private static Map<String, ChatSocket> clients = new ConcurrentHashMap<String, ChatSocket>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    // 在线用户列表
    private static Set<String> onlineUsers = new HashSet<>();

    /**
     * 接收username
     */
    private String username="";
    /**
     * 连接建立成功调用的方法
     * */

    private static List<String> list=new ArrayList<>();

    public static Set<String> getOnlineUsers() {
        return onlineUsers;
    }

    @OnOpen
    public void onOpen(Session session,@PathParam("username") String username) throws JsonProcessingException {
        log.info("现在来连接的客户："+session.getId()+"用户名："+username);
        this.username = username;
        this.session = session;
        try {
            //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
            //先给所有人发送通知，说我上线了
            Map<String,Object> map1 = new HashMap();
            map1.put("messageType",1);
            map1.put("username",username);
            sendMessageAll(JSON.toJSONString(map1),username);

            clients.put(username, this);
            //给自己发一条消息：告诉自己现在都有谁在线
            Map<String,Object> map2 = Maps.newHashMap();
            map2.put("messageType",3);
            //移除掉自己
            Set<String> set = clients.keySet();
            map2.put("onlineUsers",set);
            sendMessageTo(JSON.toJSONString(map2),username);
        }
        catch (IOException e){
            log.info(username+"上线的时候通知所有人发生了错误");
        }

    }

    @OnClose
    public void onClose() {
//        webSocketSet.remove(this);
//        onlineUsers.remove(this.username);
        clients.remove(username);
        try {
            //messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
            Map<String,Object> map1 = Maps.newHashMap();
            map1.put("messageType",2);
            map1.put("onlineUsers",clients.keySet());
            map1.put("username",username);
            sendMessageAll(JSON.toJSONString(map1),username);
        }
        catch (IOException e){
            log.info(username+"下线的时候通知所有人发生了错误");
        }
    }

//    /**
//     * 收到客户端消息后调用的方法
//     * @param message 客户端发送过来的消息*/
//    @OnMessage
//    public void onMessage(String message, Session session) throws JsonProcessingException {
//        log.info("收到来"+username+"的信息:"+message);
//        ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//        // 解析消息
//        ChatMessages chatMessages = objectMapper.readValue(message, ChatMessages.class);
//        String sender = chatMessages.getSender();
//        String receiver = chatMessages.getReceiver();
//        String content = chatMessages.getContent();
//
//
//        ChatMessages chatMessage = new ChatMessages();
//        chatMessage.setSender(chatMessages.getSender());
//        chatMessage.setReceiver(chatMessages.getReceiver());
//        chatMessage.setContent(chatMessages.getContent());
//        chatMessage.setTimestamp(Timestamp.valueOf(LocalDateTime.now()));
//        //群发消息  推送给客服端
//        for (ChatSocket item : webSocketSet) {
//            if (receiver != null && receiver.equals(item.username) || sender.equals(item.username)) {
//            try {
//
//
//                if(receiver != null && receiver.equals(item.username)){
//                    chatMessageRepositoryStatic.save(chatMessage);
//                }
//                item.sendMessage(objectMapper.writeValueAsString(chatMessages));
////                item.sendMessage(message);
//
//            } catch (IOException e) {
//                log.error(e.getMessage(),e);
//            }
//            }
//        }
//    }


    @OnError
    public void onError(Session session, Throwable error) {
        log.info("服务端发生了错误"+error.getMessage());
    }

    @OnMessage
    public void onMessage(String message, Session session)
    {
        try {
            log.info("来自客户端消息：" + message+"客户端的id是："+session.getId());
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            ChatMessages chatMessages = objectMapper.readValue(message, ChatMessages.class);
            JSONObject jsonObject = JSON.parseObject(message);
            String content = chatMessages.getContent();
            String sender = chatMessages.getSender();
            String receiver = chatMessages.getReceiver();
            //如果不是发给所有，那么就发给某一个人
            //messageType 1代表上线 2代表下线 3代表在线名单  4代表普通消息
            Map<String,Object> map1 = Maps.newHashMap();
            map1.put("messageType",4);
            map1.put("content",content);
            map1.put("sender",sender);
            if(receiver.equals("All")){
                map1.put("tousername","所有人");
                sendMessageAll(JSON.toJSONString(map1),receiver);
            }
            else{
                map1.put("tousername",receiver);
                 ChatMessages chatMessage = new ChatMessages();
                 chatMessage.setSender(chatMessages.getSender());
                 chatMessage.setReceiver(chatMessages.getReceiver());
                 chatMessage.setContent(chatMessages.getContent());
                 chatMessage.setTimestamp(Timestamp.valueOf(LocalDateTime.now()));
                 chatMessageRepositoryStatic.save(chatMessage);
                 sendMessageTo(JSON.toJSONString(map1),receiver);
            }
        }
        catch (Exception e){
            log.info("发生了错误了");
        }

    }



//    /**
//     * 实现服务器主动推送
//     */
//    private void sendMessage(String message) throws IOException {
//        this.session.getBasicRemote().sendText(message);
//    }


//    /**
//     * 群发自定义消息
//     * */
//    public static void sendInfo(SocketMsg socketMsg,@PathParam("sid") String sid) throws IOException {
//        String message = JSONObject.toJSONString(socketMsg);
//        log.info("推送消息到"+sid+"，推送内容:"+message);
//        for (ChatSocket item : webSocketSet) {
//            try {
//                //这里可以设定只推送给这个sid的，为null则全部推送
//                if(sid==null) {
//                    item.sendMessage(message);
//                }else if(item.username.equals(sid)){
//                    item.sendMessage(message);
//                }
//            } catch (IOException ignored) { }
//        }
//    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ChatSocket that = (ChatSocket) o;
        return Objects.equals(session, that.session) &&
                Objects.equals(username, that.username);
    }

    @Override
    public int hashCode() {
        return Objects.hash(session, username);
    }


    public void sendMessageTo(String message, String ToUserName) throws IOException {
        for (ChatSocket item : clients.values()) {
            if (item.username.equals(ToUserName) ) {
                item.session.getAsyncRemote().sendText(message);
                break;
            }
        }
    }

    public void sendMessageAll(String message,String FromUserName) throws IOException {
        for (ChatSocket item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }
}
